package com.android.clinic.app.ui.video;

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Chronometer;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.android.clinic.app.ClinicApplication;
import com.android.clinic.app.R;
import com.android.clinic.app.utils.Constants;
import com.jiongbull.jlog.JLog;

import org.json.JSONException;
import org.json.JSONObject;

import io.agora.AgoraAPI;
import io.agora.AgoraAPIOnlySignal;
import io.agora.IAgoraAPI;
import io.agora.rtc.RtcEngine;
import io.agora.rtc.video.VideoCanvas;

/**
 * 视频通话
 * Created by cheng on 2018/6/25.
 */
public class CallActivity extends AppCompatActivity implements ClinicApplication.OnAngoraEngineInterface {

    private static final int PERMISSION_REQ_ID_RECORD_AUDIO = 22;
    private static final int PERMISSION_REQ_ID_CAMERA = PERMISSION_REQ_ID_RECORD_AUDIO + 1;
    private static final int PERMISSION_REQ_ID_STORAGE = PERMISSION_REQ_ID_CAMERA + 1;

    private AgoraAPIOnlySignal mAngoraAPI;
    private RtcEngine mRtcEngine;

    /**远端/本地视图view*/
    private FrameLayout layRemoteVideoView, layLocalVideoView;

    /**用户信息*/
    private RelativeLayout layUserInfo;
    private ImageView ivUserHead;
    private TextView tvName, tvHint;

    /**视频通话布局*/
    private RelativeLayout layCallIn;
    private TextView tvHangupInfo;
    private LinearLayout layCallInPickup, laySwitchCamera;

    /**发起视频取消布局*/
    private LinearLayout layCallRefuse;
    private TextView tvRefuseInfo;

    /**
     * 时间计时器
     */
    private Chronometer mChronometer;
    private int miss = 0;

    private String account;
    private String channelName = "channelId";
    private MediaPlayer mPlayer;
    private int callType = -1;
    private boolean mIsCallInRefuse = false;
    private int mRemoteUid = 0;

    private String userName, userImg = "";

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_call);
        initView();
        if (checkSelfPermission(Manifest.permission.RECORD_AUDIO, PERMISSION_REQ_ID_RECORD_AUDIO)
                && checkSelfPermission(Manifest.permission.CAMERA, PERMISSION_REQ_ID_CAMERA)
                && checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, PERMISSION_REQ_ID_STORAGE)) {
            initAngoraEngineAndJoinChannel();
        }
    }

    private void initAngoraEngineAndJoinChannel() {
        initializeAngoraEngine();
        ClinicApplication.getInstance().setOnAngoraEngineInterface(this);
        setupData();
    }

    private void initView() {
        layRemoteVideoView = (FrameLayout) findViewById(R.id.remote_video_view_container);
        layLocalVideoView = (FrameLayout) findViewById(R.id.local_video_view_container);

        layUserInfo = (RelativeLayout) findViewById(R.id.layout_user_info);
        ivUserHead = (ImageView) findViewById(R.id.iv_user_head);
        tvName = (TextView) findViewById(R.id.tv_name);
        tvHint = (TextView) findViewById(R.id.tv_hint);

        layCallIn = (RelativeLayout) findViewById(R.id.layout_call_in);
        tvHangupInfo = (TextView) findViewById(R.id.tv_hangup_info);
        layCallInPickup = (LinearLayout) findViewById(R.id.layout_call_in_pickup);
        laySwitchCamera = (LinearLayout) findViewById(R.id.layout_switch_camera);

        layCallRefuse = (LinearLayout) findViewById(R.id.layout_call_refuse);
        tvRefuseInfo = (TextView) findViewById(R.id.tv_refuse_info);

        mChronometer = (Chronometer) findViewById(R.id.chronometer);
    }

    private void setupData() {
        Intent intent = getIntent();

        account = intent.getStringExtra("account");
        channelName = intent.getStringExtra("channelName");
        callType = intent.getIntExtra("type", -1);

        try {
            JSONObject jsonObject = new JSONObject(intent.getStringExtra("extra"));
            userName = jsonObject.getString("name");
            userImg = jsonObject.getString("imgUrl");
        } catch (JSONException e) {
            e.printStackTrace();
        }

        if (callType == Constants.CALL_IN) {
            mIsCallInRefuse = true;
            layCallIn.setVisibility(View.VISIBLE);
            layCallRefuse.setVisibility(View.GONE);
            tvName.setText(userName);
            tvHint.setText("邀请你视频通话...");

            try {
                mPlayer = MediaPlayer.create(this, R.raw.basic_ring);
                mPlayer.setLooping(true);
                mPlayer.start();
            } catch (Exception e) {
                e.printStackTrace();
            }
            setupLocalVideo(); // Tutorial Step 3
        }
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        JLog.e("onNewIntent");
        setupData();
    }

    @Override
    public void onFirstRemoteVideoDecoded(final int uid, int width, int height, int elapsed) {
        JLog.e("onFirstRemoteVideoDecoded  uid:" + uid);
        runOnUiThread(() -> {
            if (mRemoteUid != 0) {
                return;
            }
            mRemoteUid = uid;
            setupRemoteVideo(uid);
        });
    }

    // Tutorial Step 7
    @Override
    public void onUserOffline(final int uid, int reason) {
        runOnUiThread(() -> onRemoteUserLeft(uid));
    }

    // Tutorial Step 10
    @Override
    public void onUserMuteVideo(final int uid, final boolean muted) {
        runOnUiThread(() -> onRemoteUserVideoMuted(uid, muted));
    }

    public void onVideoCallClick(View v) {
        switch (v.getId()) {
            // 主叫方主动取消
            case R.id.layout_call_refuse:
                callOutHangup();
                break;
            // 挂断
            case R.id.layout_call_in_hangup:
                callInRefuse();
                break;
            // 接听
            case R.id.layout_call_in_pickup:
                mIsCallInRefuse = false;
                joinChannel();  // Tutorial Step 4
                mAngoraAPI.channelInviteAccept(channelName, account, 0, null);
                layCallIn.setVisibility(View.VISIBLE);
                tvHangupInfo.setText("挂断");
                layCallInPickup.setVisibility(View.GONE);
                laySwitchCamera.setVisibility(View.VISIBLE);
                layUserInfo.setVisibility(View.GONE);
                layCallRefuse.setVisibility(View.GONE);
                if (mPlayer != null && mPlayer.isPlaying()) {
                    mPlayer.stop();
                }
                startChronometer();
                break;
            // 切换摄像头
            case R.id.layout_switch_camera:
                // Tutorial Step 8
                mRtcEngine.switchCamera();
                break;
        }
    }

    private void callOutHangup() {
        if (mAngoraAPI != null)
            mAngoraAPI.channelInviteEnd(channelName, account, 0);
    }

    private void callInRefuse() {
        // "status": 0 // Default
        // "status": 1 // Busy

        JLog.e("通话时间：" + mChronometer.getText().toString());
        if (mAngoraAPI != null)
            mAngoraAPI.channelInviteRefuse(channelName, account, 0, "{\"status\":0}");

        onEncCallClicked();
        miss = 0;
    }

    @Override
    public void onJoinChannelSuccess(String channel, int uid, int elapsed) {
        JLog.e("onJoinChannelSuccess channel: " + channel + " uid: " + uid);
    }

    private void addSignalingCallback() {
        if (mAngoraAPI == null) {
            return;
        }

        mAngoraAPI.callbackSet(new AgoraAPI.CallBack() {

            @Override
            public void onLogout(final int i) {
                JLog.e("onLogout  i = " + i);
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        if (i == IAgoraAPI.ECODE_LOGOUT_E_KICKED) { // other login the account
                            Toast.makeText(CallActivity.this, "您的账户已在其他地方登陆, 当前用户被注销!", Toast.LENGTH_SHORT).show();

                        } else if (i == IAgoraAPI.ECODE_LOGOUT_E_NET) { // net
                            Toast.makeText(CallActivity.this, "因网络问题, 导致您的账号无法正常登录!", Toast.LENGTH_SHORT).show();
                            finish();
                        }
                        Intent intent = new Intent();
                        intent.putExtra("result", "finish");
                        setResult(RESULT_OK, intent);
                        finish();
                    }
                });

            }

            /**
             * 收到呼叫邀请回调
             * @param channelID
             * @param account
             * @param uid
             * @param s2
             */
            @Override
            public void onInviteReceived(final String channelID, final String account, final int uid, String s2) {
                JLog.e("onInviteReceived  channelID = " + channelID + "  account = " + account);

                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
//                      "status": 0 // Default
//                      "status": 1 // Busy
                        // 接受呼叫
                        mAngoraAPI.channelInviteRefuse(channelID, account, uid, "{\"status\":1}");

                    }
                });
            }

            /**
             * 远端已收到呼叫回调
             * @param channelID
             * @param account
             * @param uid
             */
            @Override
            public void onInviteReceivedByPeer(final String channelID, String account, int uid) {
                JLog.e("onInviteReceivedByPeer  channelID = " + channelID + "  account = " + account);

                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        layCallIn.setVisibility(View.VISIBLE);
                        layCallInPickup.setVisibility(View.GONE);
                        laySwitchCamera.setVisibility(View.VISIBLE);
                        // 开始计时
                    }
                });
            }

            /**
             * 远端已接受呼叫回调
             * @param channelID
             * @param account
             * @param uid
             * @param s2
             */
            @Override
            public void onInviteAcceptedByPeer(String channelID, String account, int uid, String s2) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        if (mPlayer != null && mPlayer.isPlaying()) {
                            mPlayer.stop();
                        }
                        layUserInfo.setVisibility(View.GONE);
                        tvRefuseInfo.setText("挂断");
                        startChronometer();
                    }
                });

            }

            /**
             * 对方已拒绝呼叫回调
             * @param channelID
             * @param account
             * @param uid
             * @param s2
             */

            @Override
            public void onInviteRefusedByPeer(String channelID, final String account, int uid, final String s2) {
                JLog.e("onInviteRefusedByPeer channelID = " + channelID + " account = " + account + " s2 = " + s2);
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        if (mPlayer != null && mPlayer.isPlaying()) {
                            mPlayer.stop();
                        }
                        if (s2.contains("status") && s2.contains("1")) {
                            Toast.makeText(CallActivity.this, "通话结束", Toast.LENGTH_SHORT).show();
                        } else {
                            Toast.makeText(CallActivity.this, "对方已挂断, 通话结束", Toast.LENGTH_SHORT).show();
                        }
                        onEncCallClicked();
                    }
                });
            }


            /**
             * 对方已结束呼叫回调
             * @param channelID
             * @param account
             * @param uid
             * @param s2
             */
            @Override
            public void onInviteEndByPeer(final String channelID, String account, int uid, String s2) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        if (channelID.equals(channelName)) {
                            Toast.makeText(CallActivity.this, "对方已挂断, 通话结束", Toast.LENGTH_SHORT).show();
                            onEncCallClicked();
                        }

                    }
                });
            }

            /**
             * 本地已结束呼叫回调
             * @param channelID
             * @param account
             * @param uid
             */
            @Override
            public void onInviteEndByMyself(String channelID, String account, int uid) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        onEncCallClicked();
                    }
                });
            }
        });
    }

    public final void showLongToast(final String msg) {
        this.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();
            }
        });
    }

    @Override
    protected void onResume() {
        super.onResume();
        addSignalingCallback();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        JLog.e("onDestroy");
        if (mPlayer != null && mPlayer.isPlaying()) {
            mPlayer.stop();
        }


        if (mRtcEngine != null) {
            mRtcEngine.stopPreview();
            mRtcEngine.leaveChannel();
        }
        mRtcEngine = null;

    }

    @Override
    public void onBackPressed() {
        JLog.e("onBackPressed callType: " + callType + " mIsCallInRefuse: " + mIsCallInRefuse);
        if (callType == Constants.CALL_IN && mIsCallInRefuse) {
            callInRefuse();
        } else {
            callOutHangup();
        }
        super.onBackPressed();
    }

    public boolean checkSelfPermission(String permission, int requestCode) {
        JLog.e("checkSelfPermission " + permission + " " + requestCode);
        if (ContextCompat.checkSelfPermission(this,
                permission)
                != PackageManager.PERMISSION_GRANTED) {

            ActivityCompat.requestPermissions(this,
                    new String[]{permission},
                    requestCode);
            return false;
        }
        return true;
    }

    @Override
    public void onRequestPermissionsResult(int requestCode,
                                           @NonNull String permissions[], @NonNull int[] grantResults) {
        JLog.e("onRequestPermissionsResult " + grantResults[0] + " " + requestCode);

        switch (requestCode) {
            case PERMISSION_REQ_ID_RECORD_AUDIO: {
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    checkSelfPermission(Manifest.permission.CAMERA, PERMISSION_REQ_ID_CAMERA);
                } else {
                    showLongToast("No permission for " + Manifest.permission.RECORD_AUDIO);
                    onEncCallClicked();
                }
                break;
            }
            case PERMISSION_REQ_ID_CAMERA: {
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, PERMISSION_REQ_ID_STORAGE);
                } else {
                    showLongToast("No permission for " + Manifest.permission.CAMERA);
                    onEncCallClicked();
                }
                break;
            }
            case PERMISSION_REQ_ID_STORAGE: {
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    initAngoraEngineAndJoinChannel();
                } else {
                    showLongToast("No permission for " + Manifest.permission.WRITE_EXTERNAL_STORAGE);
                    onEncCallClicked();
                }
                break;
            }
        }
    }

    // Tutorial Step 1
    /**
     * 初始化Agora，创建 RtcEngine 对象
     */
    private void initializeAngoraEngine() {
        mAngoraAPI = ClinicApplication.getInstance().getAngoraAPI();
        mRtcEngine = ClinicApplication.getInstance().getRtcEngine();
        JLog.e("initializeAgoraEngine mRtcEngine :" + mRtcEngine);
        if (mRtcEngine != null) {
            mRtcEngine.setLogFile("/sdcard/sdklog.txt");
        }
        setupVideoProfile();

    }

    // Tutorial Step 2
    /**
     * 打开视频模式，并设置本地视频属性
     */
    private void setupVideoProfile() {
        // 打开视频模式
        mRtcEngine.enableVideo();
        // 设置本地视频属性
        mRtcEngine.setVideoProfile(io.agora.rtc.Constants.VIDEO_PROFILE_360P, false);
    }

    // Tutorial Step 3
    /**
     * 设置本地视频显示属性
     */
    private void setupLocalVideo() {
        SurfaceView surfaceView = RtcEngine.CreateRendererView(getBaseContext());
        layRemoteVideoView.addView(surfaceView);
        mRtcEngine.setupLocalVideo(new VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_HIDDEN, 0));
        layRemoteVideoView.setVisibility(View.VISIBLE);
        int ret = mRtcEngine.startPreview();
        JLog.e("初始化视频:  setupLocalVideo startPreview enter << ret :" + ret);
    }

    // Tutorial Step 4
    /**
     * 加入一个频道
     */
    private void joinChannel() {
        // 如果不指定UID，Agroa将自动生成并分配一个UID
        JLog.e("channelName:" + channelName);
        int ret = mRtcEngine.joinChannel(null, channelName, "Extra Optional Data", 0); // if you do not specify the uid, we will generate the uid for you
        JLog.e("joinChannel enter ret :" + ret);
    }

    // Tutorial Step 5
    /**
     * 设置远端视频显示属性
     * @param uid
     */
    private void setupRemoteVideo(int uid) {
        JLog.e("setupRemoteVideo uid: " + uid + " " + layRemoteVideoView.getChildCount());
        if (layRemoteVideoView.getChildCount() >= 1) {
            layRemoteVideoView.removeAllViews();
        }

        SurfaceView surfaceViewSmall = RtcEngine.CreateRendererView(getBaseContext());
        surfaceViewSmall.setZOrderMediaOverlay(true);
        layLocalVideoView.addView(surfaceViewSmall);
        mRtcEngine.setupLocalVideo(new VideoCanvas(surfaceViewSmall, VideoCanvas.RENDER_MODE_HIDDEN, 0));
        layLocalVideoView.setVisibility(View.VISIBLE);

        SurfaceView surfaceView = RtcEngine.CreateRendererView(getBaseContext());
        layRemoteVideoView.addView(surfaceView);
        mRtcEngine.setupRemoteVideo(new VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_HIDDEN, uid));
        layRemoteVideoView.setVisibility(View.VISIBLE);
    }

    // Tutorial Step 6
    public void onEncCallClicked() {
        JLog.e("通话时间: --" + mChronometer.getText().toString());
        mChronometer.setText("");
        miss = 0;
        finish();
    }

    // Tutorial Step 7
    private void onRemoteUserLeft(int uid) {
        if (uid == mRemoteUid) {
            finish();
        }
    }

    // Tutorial Step 10
    private void onRemoteUserVideoMuted(int uid, boolean muted) {
        SurfaceView surfaceView = (SurfaceView) layRemoteVideoView.getChildAt(0);

        Object tag = surfaceView.getTag();
        if (tag != null && (Integer) tag == uid) {
            surfaceView.setVisibility(muted ? View.GONE : View.VISIBLE);
        }
    }

    /**
     * 开始计时
     */
    private void startChronometer() {
        mChronometer.setVisibility(View.VISIBLE);
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                mChronometer.start();
                mChronometer.setOnChronometerTickListener(ch -> {
                    miss++;
                    ch.setText(formatMiss(miss));
                });
            }
        }, 500);
    }

    /**
     * 将秒转化成小时分钟秒
     *
     * @param miss
     * @return
     */
    public String formatMiss(int miss) {
        String hh = miss / 3600 > 9 ? miss / 3600 + "" : "0" + miss / 3600;
        String mm = (miss % 3600) / 60 > 9 ? (miss % 3600) / 60 + "" : "0" + (miss % 3600) / 60;
        String ss = (miss % 3600) % 60 > 9 ? (miss % 3600) % 60 + "" : "0" + (miss % 3600) % 60;
        if (Integer.parseInt(hh) > 0) {
            return hh + " : " + mm + " : " + ss;
        } else {
            return mm + " : " + ss;
        }
    }
}
